package com.example.cipher;

import com.example.cipher.sm2.SM2Utils;
import com.example.cipher.sm2.Util;
import com.example.cipher.sm3.SM3Utils;
import com.example.cipher.sm4.SM4Utils;

import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.Map;

/**
 * @author yaoguangjian
 * @create 2018/12/6
 */
public class MainTest {
    public static void main(String[] args) throws Exception {
        // 参数
        String str = "{\"test\":\"001\"}";
        System.out.println("参数:" + str);

        byte[] sourceData = str.getBytes();
        // 获取公私钥
        Map<String, String> keymap = SM2Utils.generateKeyPair();
        String public_key = keymap.get("public_key");
        String private_key = keymap.get("private_key");
        System.out.println("公钥:" + public_key);
        System.out.println("私钥:" + private_key);
        // sm2+3
        String cipherText = SM2Utils.encrypt(Util.hexToByte(public_key), sourceData);
        System.out.println("sm2密文:" + cipherText);
        String plainTextEncripted = SM2Utils.decrypt(private_key, cipherText);
        System.out.println("sm2解密:" + plainTextEncripted);

        // 验签 密文完整性校验
        String sm23 = SM3Utils.encryptPlus(str, public_key);
        System.out.println("sm3加密：" + sm23);


        // sm3+4
        String key = public_key.substring(0, 16);
        System.out.println("key:" + key);
        String encryptStr = SM4Utils.EncryptStr(str, key);
        System.out.println("sm4密文:" + encryptStr);
        String DecryptStr = SM4Utils.DecryptStr(encryptStr, key);
        System.out.println("sm4解密:" + DecryptStr);
        // 验签 密文完整性校验
        String sm34 = SM3Utils.encryptPlus(str, public_key);
        System.out.println("sm3加密：" + sm34);

        System.out.println("===============");
        test1();
        // System.out.println("===============");
        // test2();

        System.out.println("==============");
        test3();

    }

    // 1. 使用非对称加密算法的公钥加密数据，私钥解密数据
    public static void test1() throws IOException {
        String sourceData = "sunhongguang";
        System.out.println("原始数据：" + sourceData);
        byte[] sourceDataBytes = sourceData.getBytes();
        // 使用SM2公钥算法的公钥进行加密
        String publicKey = "04D96E8140675F8539E756E5904423954E3EB2A0FE372269E2FFE994750C742EF779E50FD61A0D192B2E927C3C94F9F0F1BEE7C1FE779E8BFA4110F204A99E9FAE";
        // String publicKey = "9C7BA06E08E1257CBF04AB9460841FCC6AE457623956F6F3BC30CC68E2861CD32E63E0E5A9291E36164C781F4E8054888D125FDAEE16182684ADA4F0DF828691";
        String cipherText = SM2Utils.encrypt(Util.hexToByte(publicKey), sourceDataBytes);
        System.out.println("sm2密文：" + cipherText);

        // 使用sm2私钥解密
        String privateKey = "7D6CB1E6062F4F62DC02BDC89FB5EA322D9A101AF2FBB7BEDCCF0DB723912A00";
        // String privateKey = "E725A2874686B75217E62F56930611F33DE70C2D46F59DC7E94B4F75575C060C";
        String decrypt = SM2Utils.decrypt(privateKey, cipherText);
        System.out.println("sm2解密：" + decrypt);
    }

    // 2. 使用非对称加密算法的私钥加密数据，公钥解密数据 [行不通？报错]
    public static void test2() throws IOException {
        String sourceData = "sunhongguang";
        System.out.println("原始数据：" + sourceData);
        byte[] sourceDataBytes = sourceData.getBytes();

        // 使用SM2公钥算法的私钥进行加密
        String privateKey = "16CC672B9A2087F68F13FAABD2D1F81595E65FD84010D02F5FEF64731522F11B";
        String cipherText = SM2Utils.encrypt(Util.hexToByte(privateKey), sourceDataBytes);
        System.out.println("sm2密文：" + cipherText);

        // 使用sm2公钥算法的公钥进行解密
        String publicKey = "0466D9CDE39CB6AEB6DD1EB9428AAB8ACCBA47419AC2D307B3C424B6CD18752E17A429745354D0CBEECA75DEF919AB661874CE583FD64AC0FAC1592B488ED69DCA";
        String decrypt = SM2Utils.decrypt(publicKey, cipherText);
        System.out.println("sm2解密：" + decrypt);
    }

    // 3. 字符串 -> 字节 -> 十六进制
    public static void test3() {
        String str = "sunhongguang";
        System.out.println("原始字符串："+str);
        // 字符串转成字节
        byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
        System.out.println("字符串 -> 字节形式：" + bytes);

        // 字节转换成十六进制
        String hexStr = Util.byteToHex(bytes);
        System.out.println("字节 -> 十六进制形式："+hexStr);


        // String string = Util.byteToString(bytes);
        // System.out.println(string);

        // 十六进制转换成字节
        byte[] bytes1 = Util.hexToByte(hexStr);
        System.out.println("十六进制 -> 字节"+bytes1);

        // 字节转字符串
        String string = Util.byteToString(bytes1);
        System.out.println("字节 -> 字符串"+string);


        // // 字符串转十六进制
        // String hexStr1 = str2HexStr(str);
        // System.out.println("字符串 -> 十六进制"+hexStr1);
        // // 十六进制转字符串
        // String str1 = hexStr2Str(hexStr1);
        // System.out.println("十六进制 -> 字符串 "+ str1);

        String strx = "9C7BA06E08E1257CBF04AB9460841FCC6AE457623956F6F3BC30CC68E2861CD32E63E0E5A9291E36164C781F4E8054888D125FDAEE16182684ADA4F0DF828691";
        System.out.println(strx.length());

    }

    /**
     * 将字符串转为16进制
     *
     * @param str
     * @return
     */
    public static String str2HexStr(String str) {
        char[] chars = "0123456789ABCDEF".toCharArray();
        StringBuilder sb = new StringBuilder("");
        byte[] bs = str.getBytes();
        int bit;
        for (int i = 0; i < bs.length; i++) {
            bit = (bs[i] & 0x0f0) >> 4;
            sb.append(chars[bit]);
            bit = bs[i] & 0x0f;
            sb.append(chars[bit]);
            // sb.append(' ');
        }
        return sb.toString().trim();
    }

    /**
     * 将16进制转为字符串
     *
     * @param hexStr
     * @return
     */
    public static String hexStr2Str(String hexStr) {
        String str = "0123456789ABCDEF";
        char[] hexs = hexStr.toCharArray();
        byte[] bytes = new byte[hexStr.length() / 2];
        int n;
        for (int i = 0; i < bytes.length; i++) {
            n = str.indexOf(hexs[2 * i]) * 16;
            n += str.indexOf(hexs[2 * i + 1]);
            bytes[i] = (byte) (n & 0xff);
        }
        return new String(bytes);
    }


}
